/**
 * request 请求插件 - v1.0.0
 * git 地址
 * 版权/证书
 */

var util = require("common-util");
var cache = require("cache");
var service = require("common-service");
require("promise");

var Toast = require("toast");
// 提示模块实例
var SUBJECT_TOAST
/**
 * 显示提示浮层
 * @param  {String} text 提示文本
 */
function tip(text) {
    SUBJECT_TOAST && SUBJECT_TOAST.$remove();
    SUBJECT_TOAST = new Toast({
        "el": document.createElement("div")
        , "propsData": {
            "text": text
        }
    });
    SUBJECT_TOAST.$appendTo(document.body)
}

var install = function (Vue, options) {
    var uri_map = {};
    var err_code = {};
    var me = this;
    var request = (function () {
        var defConf = {
            method: 'get',
            dataType: 'json',
            cache: false,
            fresh: true,
            autoNotify: true
        }
        var defHeaders = {
            'X-Requested-With': 'XMLHttpRequest',
            // "X-Client-Id": util.getCookie('client_id'),
            // "X-Client-Token": util.getCookie('client_token'),
            "X-Client-Id": 'b2doZ1d3aHRiYmxpeElsdDd5ZEJ2a2cwdi1Oaw',
            "X-Client-Token": 'eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MDUzMjE2OTAsImFwcElkIjoid3gzNjI2OTU5MWYyN2VjM2M1IiwiZW50Q29kZSI6MTAwMDYxLCJncmFudFR5cGUiOiJjb2RlIiwib3BlbklkIjoib2doZ1d3aHRiYmxpeElsdDd5ZEJ2a2cwdi1OayIsIm1pZCI6MjYzNzYyNjEsInVpZCI6MzgyNzIyMCwibmlja05hbWUiOiLkuKvni7giLCJhbm9ueW1vdXMiOmZhbHNlfQ.OW_GpuR2H4GkLgIOB14mYeo3vGlelb5CbnO_6ZX_8cU'
        }

        /*var entId = service.getEntId();
        if (entId) {
            // 通用认证
            defHeaders["X-Ent-ID"] = entId;
        }*/

        var addQuery = function (config) {
            var query = config.query,
                url = config.url
            query = parseQuery(query)
            if (url.indexOf('?') !== -1) {
                url += '&' + query
            } else {
                url += '?' + query
            }
            config.url = url
        }
        var replaceParams = function (config) {
            var params = config.params,
                url = config.url

            Object.keys(params).forEach(function (key) {
                var reg = new RegExp('{' + key + '}', 'g')
                url = url.replace(reg, params[key])
            })
            config.url = url
        }
        var parseData = function (config) {
            var data = config.data
            if (util.isString(data)) {
                return data.replace(/\+/g, '%2B')
            }
            return JSON.stringify(data)
        }
        var parseQuery = function (query) {
            var q = []
            Object.keys(query).forEach(function (_q) {
                q.push(_q + '=' + encodeURIComponent(query[_q]))
            })
            return q.join('&')
        }
        var parseFormData = function (config) {
            var fd = new FormData
            var data = config.data
            if (util.isObject(data)) {
                Object.keys(data).forEach(function (key) {
                    fd.append(key, data[key])
                })
            }
            return fd
        }
        var getUrlHost = (function () {
            var a = document.createElement('a')
            return function (url) {
                a.href = url
                return a.host
            }
        })()

        //config 增加 autoNotify 配置，默认为true，为false则可自定义提示操作
        function request(config) {
            var xhr = new XMLHttpRequest
            var me = this
            var req = new Promise(function (resolve, reject) {
                var rawConfig = config
                config = util.extend({}, defConf, config)
                config.headers = util.extend({}, defHeaders, config.headers)
                if (uri_map.hasOwnProperty(config.url)) {
                    config.url = uri_map[config.url];
                }

                var method = config.method.toLowerCase(),
                    dataType = config.dataType.toLowerCase(),
                    headers = config.headers,
                    crossOrigin = getUrlHost(config.url) !== location.host,
                    useCache = method === 'get' && config.cache,
                    data

                if (config.fresh) {
                    config.query = util.extend({}, config.query, {
                        _: Date.now()
                    })
                }

                if (util.isObject(config.params)) {
                    replaceParams(config)
                }

                if (util.isObject(config.query)) {
                    addQuery(config)
                }

                if (!/get|head|delete/.test(method)) {
                    if (!headers.hasOwnProperty('Content-Type')) {
                        headers['Content-Type'] = 'application/json'
                    }

                    if (headers['Content-Type'] === null) {
                        // formdata 文件上传
                        delete headers['Content-Type']
                        data = parseFormData(config)
                    } else {
                        // 默认json
                        data = parseData(config)
                    }
                }

                if (useCache) {
                    // 优先从缓存中拿
                    var item = cache.get(config.url)
                    if (item) {
                        return resolve(item)
                    }
                }

                xhr.open(method, config.url, true)

                if (crossOrigin) {
                    if (config.credentials) {
                        xhr.withCredentials = true
                    }
                    delete headers['X-Requested-With']
                }

                Object.keys(headers).forEach(function (key) {
                    xhr.setRequestHeader(key, headers[key])
                });

                if (config.timeout) {
                    xhr.timeout = config.timeout
                }

                xhr.onload = function () {
                    if (request.onResponseCallback && request.onResponseCallback(this, config) === false) {
                        return
                    }
                    if (this.status >= 200 && this.status < 300 || this.status === 304) {
                        var value = this.responseText
                        if (dataType.toLowerCase() === 'json') {
                            try {
                                value = JSON.parse(value)
                            } catch (err) {
                                reject(err)
                                return
                            }
                        }
                        if (useCache) {
                            cache.set({
                                key: config.url,
                                value: value,
                                expires: config.cache
                            })
                        }

                        //兼容 code 字段
                        if (value.hasOwnProperty("code")) {
                            value.errcode = value.code;
                        }

                        //兼容 result 字段
                        if (value.hasOwnProperty("result")) {
                            value.data = value.result;
                        }

                        if (value && value.errcode === 0) {
                            resolve(value.data || {});
                        } else {
                            //如果自动提示
                            if (config.autoNotify) {
                                // 错误提示
                                // 优先取前端错误码
                                // 取不到则使用
                                var tipTxt = value.errmsg || value.message;
                                if (err_code && err_code[value.errcode]) {
                                    tipTxt = err_code[value.errcode];
                                }
                                if (tipTxt) {
                                    tip(tipTxt)
                                }
                                Vue.collect.event({
                                    "code": value.errcode
                                    , "message": value.errmsg || ""
                                    , "category": "web_error"
                                    , "action": "api_error"
                                    , "url": config.url
                                });
                                resolve(null);
                            } else {
                                if (err_code) {
                                    var tipTxt = value.errmsg || value.message;
                                    if (err_code && err_code[value.errcode]) {
                                        tipTxt = err_code[value.errcode];
                                    }
                                    var obj = value || {};
                                    obj.tip = tipTxt;
                                    reject(obj);
                                }
                            }
                        }
                    } else {
                        reject(this)
                    }
                }

                xhr.ontimeout = xhr.onerror = function (e) {
                    Vue.collect.event({
                        "code": 504
                        , "message": "api timeout"
                        , "category": "web_error"
                        , "action": "api_error"
                        , "url": config.url
                    });
                    reject(e)
                }

                xhr.onabort = function () {
                    reject({
                        type: 'abort'
                    })
                }

                if (request.onRequestCallback && request.onRequestCallback(config) === false) return

                xhr.upload.onprogress = function (e) {
                    if (e.lengthComputable) {
                        xhr.progressHandler && xhr.progressHandler(event.loaded, event.total)
                    }
                }

                xhr.send(data)
            })

            req.abort = function () {
                xhr.abort()
            }

            req.progress = function (cb) {
                xhr.progressHandler = cb
                return this
            }

            this._requestQueue = this._requestQueue || []
            this._requestQueue.push(xhr)

            return req
        }

        request.onRequest = function (callback) {
            this.onRequestCallback = callback
        }
        request.onResponse = function (callback) {
            this.onResponseCallback = callback
        }

        /**
         * 初始化地址映射对象
         * @param {Object} map 要替换的数据
         */
        request.setUriMap = function (map) {
            util.extend(uri_map, map);
            var appData = window.__APP_DATA;
            if (appData && appData.biServer) {
                var entId = service && service.getEntId() || appData.entCode;
                // 拼接biServer
                var protocol = appData.protocol || "http";
                var server;

                if (appData.biServer.indexOf("http") === -1) {
                    server = protocol + "://" + appData.biServer;
                } else {
                    server = appData.biServer;
                }

                // 拼接 entid
                /*if (entId) {
                    server = server.replace("://","://"+ entId +".");
                }*/

                Object.keys(uri_map).forEach(function (key) {
                    //不包含域名的才需要解析
                    if (uri_map[key].indexOf("https") === -1 && uri_map[key].indexOf("http") === -1) {
                        uri_map[key] = server + uri_map[key];
                    }
                });
            }

            if (appData && appData.errCode) {
                err_code = appData.errCode;
            }
        }

        return request
    })()

    Vue.http = request
    Vue.http.cancel = function (vm) {
        if (vm._requestQueue) {
            vm._requestQueue.forEach(function (req) {
                req.abort()
            })
            vm._requestQueue = null
        }
    }
    Vue.prototype.$request = request
}

module.exports = install;
